<?php

namespace app\api\service;

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\SignatureInvalidException;
use app\common\exception\ApiException;
use support\Request;

class JwtService
{
    /**
     * @var array JWT配置
     */
    protected array $config;

    /**
     * @var Request 请求实例
     */
    protected Request $request;

    /**
     * 构造函数
     * @param Request|null $request
     */
    public function __construct(?Request $request = null)
    {
        $this->config = getConfig('api.jwt');
        $this->request = $request ?? request();
    }

    /**
     * 生成JWT令牌
     * @param array $payload
     * @param int $ttl
     * @return string
     */
    public function generateToken(array $payload, int $ttl = 3600): string
    {
        $payload = array_merge($payload, [
            'iss' => $this->config['issuer'],
            'iat' => time(),
            'exp' => time() + $ttl,
        ]);
        return empty($this->config['prefix']) ? '' : ($this->config['prefix'] . ' ') . JWT::encode($payload, $this->config['secret'], $this->config['algorithms'][0]);
    }

    /**
     * 验证JWT令牌
     * @param string $token
     * @return array
     * @throws ApiException
     */
    public function verifyToken(string $token): array
    {
        try {
            $token = str_replace($this->config['prefix'] . ' ', '', $token);
            $decoded = JWT::decode($token, new Key($this->config['secret'], $this->config['algorithms'][0]));
            return (array)$decoded;
        } catch (ExpiredException $e) {
            throw new ApiException('令牌已过期', 401);
        } catch (SignatureInvalidException $e) {
            throw new ApiException('令牌签名无效', 401);
        } catch (\Exception $e) {
            throw new ApiException('令牌验证失败', 401);
        }
    }

    /**
     * 从请求头获取令牌
     * @return string
     * @throws ApiException
     */
    public function getTokenFromHeader(): string
    {
        $authHeader = $this->request->header('Authorization');
        
        if (!$authHeader) {
            throw new ApiException('缺少Authorization头', 401);
        }

        $prefix = $this->config['prefix'];
        
        if (!str_starts_with($authHeader, $prefix . ' ')) {
            throw new ApiException('Authorization头格式错误', 401);
        }

        return trim(substr($authHeader, strlen($prefix) + 1));
    }

    /**
     * 获取用户ID
     * @return int
     * @throws ApiException
     */
    public function getUserId(): int
    {
        $token = $this->getTokenFromHeader();
        $payload = $this->verifyToken($token);
        
        return (int)($payload['user_id'] ?? 0);
    }

    /**
     * 获取当前用户信息
     * @return array
     * @throws ApiException
     */
    public function getCurrentUser(): array
    {
        $token = $this->getTokenFromHeader();
        return $this->verifyToken($token);
    }

    /**
     * 刷新令牌（生成新令牌）
     * @param array $payload
     * @param int $ttl
     * @return string
     */
    public function refreshToken(array $payload, int $ttl = 3600): string
    {
        return $this->generateToken($payload, $ttl);
    }

    /**
     * 获取令牌剩余有效期
     * @param string $token
     * @return int
     * @throws ApiException
     */
    public function getTokenTTL(string $token): int
    {
        $payload = $this->verifyToken($token);
        return max(0, $payload['exp'] - time());
    }

    /**
     * 设置请求实例
     * @param Request $request
     * @return $this
     */
    public function setRequest(Request $request): static
    {
        $this->request = $request;
        return $this;
    }

    /**
     * 获取配置
     * @return array
     */
    public function getConfig(): array
    {
        return $this->config;
    }
}